//============================================================================
// Copyright (C) 2003-2013 Brett R. Jones 
// All Rights Reserved
//
// You may redistribute and/or modify for non commercial and commercial uses 
// provided this copyright notice remains in place and is not modified
//
// This code is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// brettjones1900@gmail.com
// http://www.p2panarchy.com
//============================================================================
#include "RcSysPktLib.h"
#include <VxUtilLib/VxParse.h>
#include <VxUtilLib/VxGlobals.h>
#include <VxUtilLib/VxMutex.h>

static const U32 g_u32NearbyUdpTimeout = 60;		// if haven't received udp broadcast in these seconds then user is no longer nearby
static const U32 g_u32OnlineStatusTimeout = 600;	// if haven't had udp or tcp activity in these seconds then user is no longer online

//---------------------------------------------------------------------------
RogueNetworkName::RogueNetworkName()
{
    strcpy( m_as8NetName, "RcNet" );
}

//---------------------------------------------------------------------------
const char * RogueNetworkName::getNetworkName( void )						
{ 
	return m_as8NetName; 
}

//---------------------------------------------------------------------------
void RogueNetworkName::setNetworkName( const char * pNetworkName )
{
	strcpy( m_as8NetName, pNetworkName );
}

//////////////////////////////////////////////////////////////////////////////
RogueVersion::RogueVersion() 
	: m_u8RogueVersion( RC_SYS_ROGUE_ENGINE_VERSION )
{
}

//=== methods ===//
//! get version of rogue engine
U8 RogueVersion::getRogueVersion( void )						
{ 
	return m_u8RogueVersion; 
};

//! get version of rogue engine as string
void RogueVersion::getRogueVersion( std::string& strRetRougeVersion ) 
{ 
	return StdStringFormat( strRetRougeVersion, "%d.%d", (m_u8RogueVersion >> 4)&0x0f,  m_u8RogueVersion & 0x0f ); 
}

//////////////////////////////////////////////////////////////////////////////
//=== constructor ===//
RcSysPktAnnActionData::RcSysPktAnnActionData()
	: m_u32ActionData( 0 )
	, m_u16ActionFlags(0)
	, m_u8ActionRes(0)
	, m_u8RequestFlags(0)								
{
}

void		RcSysPktAnnActionData::setIsPktAnnReplyRequested( bool bReqReply )		{ if( bReqReply )(m_u8RequestFlags |= FLAG_PKT_ANN_REQ_REPLY); else m_u8RequestFlags &= (~FLAG_PKT_ANN_REQ_REPLY); }
bool		RcSysPktAnnActionData::getIsPktAnnReplyRequested( void )				{ return (m_u8RequestFlags & FLAG_PKT_ANN_REQ_REPLY)?1:0; }
void		RcSysPktAnnActionData::setIsPktAnnRevConnectRequested( bool bReqConnect ){ if( bReqConnect )(m_u8RequestFlags |= FLAG_PKT_ANN_REQ_REV_CONNECT); else m_u8RequestFlags &= (~FLAG_PKT_ANN_REQ_REV_CONNECT); }
bool		RcSysPktAnnActionData::getIsPktAnnRevConnectRequested( void )			{ return (m_u8RequestFlags & FLAG_PKT_ANN_REQ_REV_CONNECT)?1:0; }
void		RcSysPktAnnActionData::setIsPktAnnStunRequested( bool bReqStun )		{ if( bReqStun )(m_u8RequestFlags |= FLAG_PKT_ANN_REQ_STUN); else m_u8RequestFlags &= (~FLAG_PKT_ANN_REQ_STUN); }
bool		RcSysPktAnnActionData::getIsPktAnnStunRequested( void )					{ return (m_u8RequestFlags & FLAG_PKT_ANN_REQ_STUN)?1:0; }
//////////////////////////////////////////////////////////////////////////////
//=== constructor ===//
RcSysPktAnnBase::RcSysPktAnnBase()
{
	m_u16PktType = RC_SYS_PKT_TYPE_ANNOUNCE;
}

//=== methods ===//
bool RcSysPktAnnBase::hasFriendDataChanged( RcSysPktAnnBase * poOther ) { return ( 0 == memcmp( this, poOther, sizeof( RcSysPktAnnBase ) ))?0:1;}

//! make copy
RcSysPktAnnBase *	RcSysPktAnnBase::MakeAnnBaseCopy( void )
{
	vx_assert( sizeof( RcSysPktAnnBase ) ==  m_u16PktLen );
	vx_assert( RC_SYS_PKT_TYPE_ANNOUNCE == m_u16PktType );
	char * pTemp = new char[ m_u16PktLen ];
	vx_assert( pTemp );
	memcpy( pTemp, this, m_u16PktLen );
	return ( RcSysPktAnnBase *)pTemp;
}


//////////////////////////////////////////////////////////////////////////////
//=== constructor ===//
RcSysPktAnnVolitileVars::RcSysPktAnnVolitileVars()
	: m_u32TimeUdpLastContact(0)
	, m_u8ContactFlags(0)
	, m_u8Flags(0)
	, m_u8Res3(0)
	, m_u8Res4(0)
{
}

//////////////////////////////////////////////////////////////////////////////
//---------------------------------------------------------------------------
RcSysPktAnnounce::RcSysPktAnnounce()	
{ 
	m_u16PktLen = sizeof( VxNetIdent );
	m_u16PktLen = sizeof( RcSysPktAnnounce );
	m_u16PktType = RC_SYS_PKT_TYPE_ANNOUNCE;
	vx_assert( 0 == ( sizeof( RcSysPktAnnounce ) & 0x0f ) );
}

//---------------------------------------------------------------------------
RcSysPktAnnounce *	RcSysPktAnnounce::MakeAnnCopy( void )
{
	vx_assert( sizeof( RcSysPktAnnounce ) ==  m_u16PktLen );
	vx_assert( RC_SYS_PKT_TYPE_ANNOUNCE == m_u16PktType );
	char * pTemp = new char[ m_u16PktLen ];
	vx_assert( pTemp );
	memcpy( pTemp, this, m_u16PktLen );
	return ( RcSysPktAnnounce *)pTemp;
}

//---------------------------------------------------------------------------
RcSysPktAnnounce *	RcSysPktAnnounce::MakeAnnReverseCopy( void )
{
	RcSysPktAnnounce * pTemp = MakeAnnCopy();
	pTemp->reversePermissions();
	return pTemp;
}

//---------------------------------------------------------------------------
bool RcSysPktAnnounce::isValidPktAnn( void )
{
	return ( ( m_u16PktLen == sizeof( RcSysPktAnnounce ) ) &&
			 ( m_u16PktType == RC_SYS_PKT_TYPE_ANNOUNCE ) );
}

//---------------------------------------------------------------------------
//! get seconds since any last contact
U32 RcSysPktAnnounce::getElapsedSecLastContact( void )	
{ 
	if( m_oUdpIp.isValid() ) return g_u32SysTimeSec - m_u32TimeUdpLastContact; return getElapsedSecTcpLastContact(); 
}

//---------------------------------------------------------------------------
//! get seconds since last tcp contact
U32 RcSysPktAnnounce::getElapsedSecTcpLastContact( void )	
{ 
	return g_u32SysTimeSec - m_u32TimeTcpLastContact; 
}

//---------------------------------------------------------------------------
//! online status expires if no activity for specified time 
bool RcSysPktAnnounce::isOnlineStatusExpired( void )
{
	if( isIgnored() )
	{
		return true;
	}
	if( false == isNearbyStatusExpired() )
	{
		return false;
	}
	if( g_u32OnlineStatusTimeout >= ( g_u32SysTimeSec - m_u32TimeTcpLastContact ) )
	{
		return false;
	}
	return true;
}

//---------------------------------------------------------------------------
//! determine if udp timeout has expired ( used for guest permissions and nearby status )
bool RcSysPktAnnounce::isNearbyStatusExpired( void )
{
	if( g_u32NearbyUdpTimeout <= ( g_u32SysTimeSec - m_u32TimeUdpLastContact ) )
	{
		return true;
	}
	return false;
}
//---------------------------------------------------------------------------
//! if nearby then make permissions at least guest
void RcSysPktAnnounce::updateNearbyPermissions( void )
{
	if( false == isNearbyStatusExpired() )
	{
		if( false == isIgnored() )
		{
			if( eFriendStateGuest > getMyFriendshipToHim() )
			{
				setMyFriendshipToHim(eFriendStateGuest);
			}
			if( eFriendStateGuest > getHisFriendshipToMe() )
			{
				setHisFriendshipToMe(eFriendStateGuest);
			}
		}
	}
}



//---------------------------------------------------------------------------
//! dump contents of pkt announce for debug
void RcSysPktAnnounce::DebugDump( void )
{
	std::string strName;
	std::string strDesc;
	std::string strNetwork;
	std::string strIp;
	std::string strId;

	this->getMyOnlineId( strId );
	this->getMyOnlineIPv4( strIp );
	U16 u16Port = this->getOnlinePort();
	this->getOnlineName( strName );
	this->getOnlineDescription( strDesc );
	strNetwork = this->getNetworkName();

	log_msg( 0, "RcSysPktAnnounce Len %d Version #%d name %s Ip %s Port %d desc %s network %s\n",
			m_u16PktLen,		// packet length
			m_u8PktVersion,		// version of program
			strName.c_str(),		
			strIp.c_str(),		// IP of announcer
			u16Port,			// Port announcer listens on
			strDesc.c_str(),
			strNetwork.c_str()
			);		
}

